package com.wskeee.ec.components.list
{
	import com.wskeee.ec.components.BasePanel;
	import com.wskeee.ec.components.VScrollBar;
	import com.wskeee.ec.containers.Container;
	import com.wskeee.ec.core.EComponent;
	import com.wskeee.ec.core.EGlobal;
	import com.wskeee.ec.interfaces.IList;
	import com.wskeee.ec.interfaces.IListCellRenderer;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	
	public class ListBase extends BasePanel implements IList
	{
		//-----------------------------------------------------------------
		//  static variables
		//-----------------------------------------------------------------
		//---------------------
		//att
		//---------------------
		//保存所有 item 数据 格式 = {labelFiled:xx}
		protected var items:Object = [];
		protected var renders:Vector.<IListCellRenderer>;
		protected var renderBox:Container;
		
		public function ListBase()
		{
			super();
			border = true;
			width = 100;
		}
		
		//========================= init ========================
		override protected function initEvent():void
		{
			super.initEvent();
			addEventListener(Event.RESIZE,onResizeHandler);
			addEventListener(MouseEvent.MOUSE_WHEEL,onMouseWheelHandler);
		}
		
		private function onMouseWheelHandler(event:MouseEvent):void
		{
			scrollToIndex(scrollItemIndex + (event.delta<0 ? 1 : -1));
		}
		
		private function onResizeHandler(evt:Event):void
		{
			invalidateRecreateRender();
			reflashVScrollBar();
			invalidateDisplayList();
		}
		
		override protected function initChildren():void
		{
			super.initChildren();
			initRenderBox();
			initVScrollBar();
		}
		//========================= end =========================
		
		//========================= renderBox ===================
		/**
		 * renderbox为一个容器，主要放置render item
		 * 不同的list可以拥有不同的容器，以改变render的排列 
		 */
		protected function initRenderBox():void
		{
			//overrride
		}
		//========================= end =========================
		
		//========================= system render ===============
		override protected function commitProperties():void
		{
			super.commitProperties();
			if(invalidateRecreateRenderFlag)
			{
				createRender();
				invalidateRecreateRenderFlag = false;
				invalidateReflashRender();
			}
			if(invalidateReflashRenderFlag)
			{
				reflashRender();
				invalidateReflashRenderFlag = false;
			}
		}
		
		override protected function measure():void
		{
			measureWidth = explicitWidth;
			measureHeight = explicitHeight;
			if(isNaN(explicitWidth))
				measureWidth = 100;
			if(isNaN(explicitHeight))
				measureHeight = itemHeight * (dataProvider ? (dataProvider.length<6 ? dataProvider.length : 6) : 1); 
			if(isNaN(explicitWidth) || isNaN(explicitHeight))
				setActualSize(measureWidth,measureHeight);
		}
		
		override protected function updateDisplayList():void
		{
			super.updateDisplayList();
			if(wentScrollToIndex!=-1)
			{
				vScrollbar.scrollPosition = getScrollIndexToScrollBarPosition(wentScrollToIndex);
				wentScrollToIndex = -1;
			}
		}
		//========================= end =========================
		
		
		
		//========================= act ========================
		public function addItem(item:Object):void
		{
			addItemAt(item,items.length);
		}
		
		public function addItemAt(item:Object, index:int):void
		{
			if(index>=0 && index<=items.length)
			{
				items.splice(index,0,item);
				if(index<selectedIndex)
					selectedIndex++;
				reflashVScrollBar();
				if(isNeedReflashRender(index))
					invalidateReflashRender();
				if(isNeedReCreateRender())
					invalidateRecreateRender();
			}
		}
		
		public function removeItem(item:Object):void
		{
			removeItemAt(getItemIndex(item));
		}
		
		public function removeItemAt(index:int):void
		{
			if(index>=0 && index<items.length)
			{
				items.splice(index,1);
				
				if(index<selectedIndex)
					selectedIndex--;
				if(items.length == 0)
					selectedIndex = -1;
				
				dispatchEvent(new Event(Event.CHANGE));
				reflashVScrollBar();
				if(isNeedReflashRender(index))
					invalidateReflashRender();
				if(isNeedReCreateRender())
					invalidateRecreateRender();
			}
		}
		
		public function removeAll():void
		{
			items = [];
			destroyRender();
		}
		
		public function getItemAt(index:int):Object
		{
			if(index>=0 && index<items.length)
				return items[index];
			return null;
		}
		
		public function getItemRendererAt(index:int):IListCellRenderer
		{
			if(index>=0 && index<items.length)
				return renders[index];
			return null;
		}
		
		//--------------------------------------------------------------------------
		//
		//  public method
		//
		//--------------------------------------------------------------------------
		/**
		 * 手动滚动到指定索引 
		 * @param value
		 * 
		 */
		
		protected var wentScrollToIndex:int = -1;
		public function scrollToIndex(value:int):void
		{
			if(value != -1 && value != wentScrollToIndex)
			{
				wentScrollToIndex = value;
				invalidateDisplayList();
			}
		}
		
		//---------------------
		//itemRenderer
		//---------------------
		//ItemRenderer 改变标志
		protected var needRecreateRender:Boolean = false;
		private var ItemRenderer:Class;
		public function set itemRenderer(value:Class):void
		{
			if(value && ItemRenderer!=value)
			{
				ItemRenderer = value;
				needRecreateRender = true;
				invalidateDisplayList();
			}
		}
		
		public function get itemRenderer():Class
		{
			return ItemRenderer;
		}
		
		//---------------------
		//labelFiled
		//---------------------
		private var _labelField:String = "label";
		public function set labelField(value:String):void
		{
			_labelField = value;
			invalidateProperties();
		}
		public function get labelField():String
		{
			return _labelField;
		}
		
		//---------------------
		//dataProvider
		//---------------------
		protected var _dataProvider:Object;
		public function get dataProvider():Object
		{
			return _dataProvider;
		}
		public function set dataProvider(value:Object):void
		{
			if(value && value.hasOwnProperty("length"))
			{
				_dataProvider = value;
				items = _dataProvider;
				reflashVScrollBar();
				invalidateRecreateRender();
				invalidateSize();
				return;
			}
		}
		
		//---------------------
		//selectedItem
		//---------------------
		public function get selectedItem():Object
		{
			return getItemAt(selectedIndex);
		}
		
		//---------------------
		//selectedItems
		//---------------------
		public function get selectedItems():Vector.<Object>
		{
			var len:int = selectedIndexs.length;
			var _selectedItems:Vector.<Object> = new Vector.<Object>(len);
			for(var i:int=0;i<len;i++)
				_selectedItems[i] = getItemAt(selectedIndexs[i]);
			return _selectedItems;
		}
		
		//---------------------
		//selectedIndex
		//---------------------
		public function set selectedIndex(value:int):void
		{
			if(value>=-1 && selectedIndex!=value)
			{
				_selectedIndexs = new <int>[value];
				invalidateReflashRender();
				dispatchEvent(new Event(Event.CHANGE));
			}
		}
		public function get selectedIndex():int
		{
			return _selectedIndexs[0];
		}
		
		//---------------------
		//selectedIndexs
		//---------------------
		protected var _selectedIndexs:Vector.<int> = new <int>[-1];
		public function get selectedIndexs():Vector.<int>
		{
			return _selectedIndexs;
		}
		public function set selectedIndexs(value:Vector.<int>):void
		{
			if(!value || value.length==0)value = new <int>[-1];
			_selectedIndexs = value;
			invalidateReflashRender();
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		//---------------------
		//allowMultipleSelection
		//---------------------
		private var _allowMultipleSelection:Boolean;
		public function set allowMultipleSelection(bo:Boolean):void
		{
			_allowMultipleSelection = bo;
			invalidateReflashRender();
		}
		public function get allowMultipleSelection():Boolean
		{
			return _allowMultipleSelection;
		}
		
		//---------------------
		//itemHeight
		//---------------------
		private var _itemHeight:Number = 18;
		public function set itemHeight(value:Number):void
		{
			if(_itemHeight!=value)
			{
				_itemHeight = value;
				invalidateRecreateRender();
				reflashVScrollBar();
			}
		}
		public function get itemHeight():Number
		{
			return _itemHeight;
		}
		
		//---------------------
		//autoHideScrollBar
		//---------------------
		private var _autoHideScrollbar:Boolean;
		public function set autoHideScrollbar(bo:Boolean):void
		{
			_autoHideScrollbar = bo;
			onResizeHandler(null);
		}
		public function get autoHideScrollbar():Boolean
		{
			return _autoHideScrollbar;
		}
		
		//---------------------
		//defaultColor
		//---------------------
		public function set defaultColor(value:Object):void
		{
			setStyle("defaultColor", value);
			invalidateRecreateRender();
		}
		public function get defaultColor():Object
		{
			return getStyle("defaultColor");
		}
		//---------------------
		//defaultColorAlpha
		//---------------------
		public function set defaultAlpha(value:Number):void
		{
			setStyle("defaultAlpha", value);
			invalidateRecreateRender();
		}
		public function get defaultAlpha():Number
		{
			return getStyle("defaultAlpha") as Number;
		}
		//---------------------
		//rolloverColor
		//---------------------
		public function set rolloverColor(value:Object):void
		{
			setStyle("rolloverColor", value);
			invalidateRecreateRender();
		}
		public function get rolloverColor():Object
		{
			return getStyle("rolloverColor");;
		}
		//---------------------
		//rolloverColorAlpha
		//---------------------
		public function set rolloverAlpha(value:Number):void
		{
			setStyle("rolloverAlpha", value);
			invalidateRecreateRender();
		}
		public function get rolloverAlpha():Number
		{
			return getStyle("rolloverAlpha") as Number;
		}
		
		//---------------------
		//selectedColor
		//---------------------
		public function set selectedColor(value:Object):void
		{
			setStyle("selectedColor", value);
			invalidateRecreateRender();
		}
		public function get selectedColor():Object
		{
			return getStyle("selectedColor");
		}
		//---------------------
		//selectedColorAlpha
		//---------------------
		public function set selectedAlpha(value:Number):void
		{
			setStyle("selectedAlpha", value);
			invalidateRecreateRender();
		}
		public function get selectedAlpha():Number
		{
			return getStyle("selectedAlpha") as Number;
		}
		
		//---------------------
		//destory
		//---------------------
		override public function destory():void
		{
			removeEventListener(Event.RESIZE,onResizeHandler);
			removeEventListener(MouseEvent.MOUSE_WHEEL,onMouseWheelHandler);
			removeAll();
			destoryVScroll();
			super.destory();
		}
		//========================= end =========================
		
		//========================= protected act ===============
		//---------------------
		//invalidateReCreateRender
		//---------------------
		/**
		 * 需要重新创建 render 标志，当为 true 时
		 * 在下一次更新将会重新创建所有render 
		 */
		private var invalidateRecreateRenderFlag:Boolean = false;
		/**
		 * 设置重新创建 render 
		 * 
		 */
		protected function invalidateRecreateRender():void
		{
			invalidateRecreateRenderFlag = true;
			invalidateProperties();
		}
		
		//---------------------
		//invalidateReflashRender
		//---------------------
		/**
		 * 需要重新更新 render 数据，当 selectedIndex 发生改变，需要重新设置 render 数据 
		 * 以达到数据滚动效果,当前为 ture 时下一更新将更新所有render
		 */
		private var invalidateReflashRenderFlag:Boolean = false;
		/**
		 * 设置重新更新可视 render 
		 * 
		 */
		protected function invalidateReflashRender():void
		{
			invalidateReflashRenderFlag = true;
			invalidateProperties();
		}
		//---------------------
		//invalidate
		//---------------------
		/**
		 * 创建 item Render 
		 * render 为list 显示列表的最小单元，将list数据以可视化显示出来。
		 * render 由 ItemRenderer 决定。
		 * 而所有 ItemRenderer 都实现 IListCellRenderer 接口
		 */;
		protected function createRender():void
		{
			destroyRender();
			var item:IListCellRenderer;
			var len:int = Math.min(itemnum,maxRenderNum);
			len = Math.max(0,len);
			renders = new Vector.<IListCellRenderer>(len);
				
			for(var i:int=0;i<len;i++)
			{
				item = new ItemRenderer() as IListCellRenderer;
				initRenderItem(item);
				renders[i] = item;
				renderBox.addChild(item as DisplayObject);
			}
			
			renderBox.scrollRect = new Rectangle(0,0,listContentWidth,height);
		}
		
		/**
		 * 初始 render item，可以子类复盖 增删功能  
		 * @param item
		 * 
		 */
		protected function initRenderItem(item:IListCellRenderer):void
		{
			item.list = this;
			item.addEventListener(MouseEvent.CLICK,onItemClick);
			EComponent(item).setActualSize(listContentWidth,itemHeight);
		}
		
		protected function onItemClick(evt:MouseEvent):void
		{
			var render:IListCellRenderer = evt.currentTarget as IListCellRenderer;
			var index:int = getItemIndex(render.data);
			doSelected(index);
		}
		
		/**
		 * 选择触发 
		 * @param index		item.index
		 * 
		 */
		protected function doSelected(index:int):void
		{
			if(allowMultipleSelection)
			{
				if(EGlobal.keyboardManager.ctrlIsDown)
					selectedIndexs = doSelectedIndex(selectedIndexs,index,!isSelected(index));
				else
					selectedIndexs = isSelected(index) ? new <int>[-1] : new <int>[index];
			}else
			{
				if(selectedIndex != index)
					selectedIndexs = new <int>[index];
			}
			onSelected(index);
		}
		
		/**
		 * 选择后调用 
		 * 
		 */
		protected function onSelected(index:int):void
		{
			//overide
		}
		
		/**
		 * 销毁 rander item，可重写增删功能 
		 * @param item
		 * 
		 */
		protected function destoryRenderItem(item:IListCellRenderer):void
		{
			item.removeEventListener(MouseEvent.CLICK,onItemClick);
			renderBox.removeChild(item as DisplayObject);
			item.destory();
		}
		
		/**
		 * 销毁 所有 render 
		 * 
		 */
		protected function destroyRender():void
		{
			var render:IListCellRenderer;
			while(renders && renders.length>0)
			{
				render = renders[0];
				destoryRenderItem(render);
				renders.splice(0,1);
			}
		}
		
		/**
		 * 刷新 item Render 显示 
		 * 
		 */
		protected function reflashRender():void
		{
			//---------------------
			//override 移动 render 更新 render
			//---------------------
			
			//显示已选择项
			for(var i:int=0,len:int=renders.length;i<len;i++)
				renders[i].selected = isSelected(getItemIndex(renders[i].data));
			//Logger.debug(selectedIndexs);
		}
		
		//========================= end =========================
		
		
		//========================= utils =======================
		/**
		 * 检查是否包括 item 对象 
		 * @param item
		 * @return 
		 * 
		 */
		protected function isContains(item:Object):Boolean
		{
			return items.indexOf(item) != -1;
		}
		
		/**
		 * 检查是否选择 
		 * @param index
		 * @return 
		 * 
		 */
		protected function isSelected(index:int):Boolean
		{
			return selectedIndexs.indexOf(index) != -1;
		}
		
		/**
		 * 获取 item 的索引 
		 * @param item
		 * @return 
		 * 
		 */
		protected function getItemIndex(item:Object):int
		{
			return items.indexOf(item);
		}
		
		/**
		 * 操作 selectedIndex
		 * @param index		
		 * @param isAdd		是否添加
		 * 
		 */
		protected function doSelectedIndex(indexs:Vector.<int>,index:int,isAdd:Boolean=false):Vector.<int>
		{
			if(!isAdd)
			{
				indexs.splice(selectedIndexs.indexOf(index),1);
			}else
			{
				if(indexs[0]==-1)indexs.length = 0;
				indexs.push(index);
			}
			indexs.sort(Array.NUMERIC);
			return indexs;
		}
		
		/**
		 * 是否需要刷新 可视区的 render
		 * eg：如果 selectedIndex = 0,而新添加一个item在索引 1 位置，这种情况下需要重新刷新可视区 
		 * 默认情况下返回 false ,如果需要更新，可以子类 overrder 些方法
		 * @param index
		 * @return 
		 * 
		 */
		protected function isNeedReflashRender(index:int):Boolean
		{
			return false;
		}
		
		/**
		 * 是否需要重新创建 可视区render
		 * eg：如果 当前 itemnum = 2 ，新添加一个item后，render 数无法满足显示，这种情况下必须重新创建可视区render
		 * 默认情况下返回 false ,如果需要更新，可以子类 overrder 些方法
		 * @return 
		 * 
		 */
		protected function isNeedReCreateRender():Boolean
		{
			return false;
		}
		
		/**
		 * 计算 要显示 指定 索引 item 时，滚动条需要滚动到的位置 
		 * @return 
		 * 
		 */
		protected function getScrollIndexToScrollBarPosition(value:int):Number
		{
			//不同 layout 可以重写
			//scrollItemIndex = Math.round(vScrollbar.scrollPosition/vScrollbar.maxScrollPosition * validScrollItemNum);
			value = Math.min(value,validScrollItemNum);
			return value/validScrollItemNum*vScrollbar.maxScrollPosition;
		}
		
		/**
		 * 所有 item 总数 
		 * @return 
		 * 
		 */
		protected function get itemnum():int
		{
			return items.length;
		}
		
		/**
		 * 根据高度和itemHeight决定 render的数目 
		 * @return 
		 * 
		 */
		protected function get maxRenderNum():int
		{
			return Math.ceil(height/itemHeight);
		}
		
		/**
		 * 获取需要滚动的item数,当最后一个item超出边界时，
		 * 需要多加1使最后一个item也要以全部显示 
		 * @return 
		 * 
		 */
		protected function get validScrollItemNum():int
		{
			var overHeight:Boolean = maxRenderNum*itemHeight>height;
			return itemnum - maxRenderNum + (overHeight ? 1 : 0);
		}
		
		/**
		 * 判断是否显示滚动条 
		 * @return 
		 * 
		 */
		protected function get isNeedScrollBar():Boolean
		{
			if(height<(16+16))return false;
			return autoHideScrollbar ? itemnum>maxRenderNum : true;
		}
		
		/**
		 * 列表内容宽度，不包括滚动条，
		 * 当设置  autoHideScrollbar = true 并且 列表数少于最大可显示数时，滚动条自动隐藏
		 * @return 
		 * 
		 */
		protected function get listContentWidth():Number
		{
			return width - (isNeedScrollBar ? 16 : 0);
		}
		//========================= end =========================
		
		//========================= scroll ======================
		/**
		 *　当前 滚动到的 item 索引 
		 */
		protected var scrollItemIndex:int = 0;
		public var vScrollbar:VScrollBar;
		protected function initVScrollBar():void
		{
			vScrollbar = new VScrollBar();
			vScrollbar.addEventListener(Event.CHANGE,onVScroll);
			addChild(vScrollbar);
		}
		
		protected function onVScroll(event:Event):void
		{
			scrollItemIndex = Math.round(vScrollbar.scrollPosition/vScrollbar.maxScrollPosition * validScrollItemNum);
			if(scrollItemIndex<0)
				scrollItemIndex = 0;
			invalidateReflashRender();
		}
		
		protected function destoryVScroll():void
		{
			vScrollbar.removeEventListener(Event.CHANGE,onVScroll);
		}
		
		/**
		 * 当 组件 size 改变，或者 list item 改变时调用  
		 * 由 子类重写
		 */
		protected function reflashVScrollBar():void
		{
			//override 
			vScrollbar.visible = isNeedScrollBar;
		}
		//========================= end =========================
	}
}